#ifndef Utils_h
#define Utils_h

#include <osg/NodeVisitor>
#include <osg/BoundingBox>
#include <osg/Geode>
#include <osg/BoundingSphere>

#include <osgGA/GUIEventHandler>

// BOUNDING BOX UTILS

class  ComputeBoundingBox : public osg::NodeVisitor {
	public:

    ComputeBoundingBox() : NodeVisitor( NodeVisitor::TRAVERSE_ALL_CHILDREN ) {}
    
    virtual ~ComputeBoundingBox() {}


    void apply( osg::Geode &geode ) {
        osg::BoundingBox bbox;
        // std::cout << "numChild : " << geode.getNumDrawables() << std::endl;
        for(  unsigned int i = 0; i < geode.getNumDrawables(); ++i ){
            bbox.expandBy( geode.getDrawable(i)->getBound());
		//    std::cout << "Node name :" << geode.getName() << std::endl;
		 //   std::cout << std::endl;
            }
		
		osg::MatrixList mat = geode.getWorldMatrices();
		applyMatrixToBoundingBox(bbox, mat[0]);
        traverse( geode );

        } 

	/// Replace bounding box in the world coord space
	void applyMatrixToBoundingBox(osg::BoundingBox & bbox, const osg::Matrix & mat) {
			osg::Vec3 v1(bbox.xMin(),bbox.yMin(),bbox.zMin());
			v1 = v1 * mat;
			osg::Vec3 v2(bbox.xMin(),bbox.yMin(),bbox.zMax());
			v2 = v2 * mat;
			osg::Vec3 v3(bbox.xMin(),bbox.yMax(),bbox.zMin());
			v3 = v3 * mat;
			osg::Vec3 v4(bbox.xMin(),bbox.yMax(),bbox.zMax());
			v4 = v4 * mat;
			osg::Vec3 v5(bbox.xMax(),bbox.yMin(),bbox.zMin());
			v5 = v5 * mat;
			osg::Vec3 v6(bbox.xMax(),bbox.yMin(),bbox.zMax());
			v6 = v6 * mat;
			osg::Vec3 v7(bbox.xMax(),bbox.yMax(),bbox.zMin());
			v7 = v7 * mat;
			osg::Vec3 v8(bbox.xMax(),bbox.yMax(),bbox.zMax());
			v8 = v8 * mat;

			bbox.init();

			bbox.expandBy(v1);
			bbox.expandBy(v2);
			bbox.expandBy(v3);
			bbox.expandBy(v4);
			bbox.expandBy(v5);
			bbox.expandBy(v6);
			bbox.expandBy(v7);
			bbox.expandBy(v8);
			m_boundingBox = bbox;
			m_boundingBoxs.push_back(bbox);

		}

    
    /// Return bounding box
    osg::BoundingBox &getBoundBox() { return m_boundingBox; }  
    std::vector<osg::BoundingBox> &getBoundBoxs() { return m_boundingBoxs; }  


protected :
    osg::BoundingBox m_boundingBox; ///< bounding box 
    std::vector<osg::BoundingBox> m_boundingBoxs; ///< bounding box         
};

// KEYBOARD UTILS

class KeyboardState {
private:
	bool m_keyup;
public:
	KeyboardState() : m_keydown(false), m_keyup(false) {}
	bool m_keydown;
	inline bool isUp(){bool up = m_keyup; m_keyup = false; return up;}
	inline void setUp(bool up){m_keyup = up;}
	osgGA::GUIEventAdapter::KeySymbol m_key;
};

class KeyboardEventHandler : public osgGA::GUIEventHandler {
    
public:
	KeyboardEventHandler(KeyboardState* keyState) {
		m_pkeyState = keyState;
	}


	virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa) {
       switch(ea.getEventType()) {
       case(osgGA::GUIEventAdapter::KEYDOWN):
			m_pkeyState->m_key = (osgGA::GUIEventAdapter::KeySymbol)ea.getKey();
			m_pkeyState->setUp(false);
			m_pkeyState->m_keydown = true;
			return false;
	   case(osgGA::GUIEventAdapter::KEYUP):
			m_pkeyState->m_keydown = false;
			m_pkeyState->setUp(true);
			return false;
       default:
			return false;
       }
	}

    virtual void accept(osgGA::GUIEventHandlerVisitor& v)   { v.visit(*this); };

protected:
	KeyboardState* m_pkeyState;
};



 
#endif 


